- blog/
Building Your Own OpenTelemetry Stack: A .NET Developer's Tutorial with Jaeger, Prometheus, and the OpenTelemetry Collector
In a previous post I wrote about how to get started with deploying the OpenTelemetry collector to AWS Fargate. But doing this every time to test you metrics and traces is not very efficient. Besides that it is also hard to debug. In a world of devops we want a fast feedback loop. So how can we do this?
In this blog post I will show you how to setup a local OpenTelemetryCollector stack to test your metrics and traces before deploying them.
We create this from scratch. So we will start with a simple application that will generate some metrics and traces. After that we will add the OpenTelemetry collector to collect the metrics and traces. And finally we will use Jaeger for the tracing and add Prometheus to collect the metrics.
The application #
In this example we will use a simple ASP.NET Core application. The so called Weather api.
To create a new project execute the following command:
mkdir src && cd src
dotnet new webapi -o WeatherApi
Next we will add the OpenTelemetry packages to the project.
cd WeatherApi
dotnet add package OpenTelemetry
dotnet add package OpenTelemetry.Extensions.Hosting
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol
First we need to create a meter to collect the metrics. Create a new file WeatherMeter.cs and add the following code to the file.
|
|
Here we create a new meter and a counter. The counter will be used to count the number of requests to the WeatherForecastController. The GetWeatherForecast method is a wrapper around the counter and will ensure that the counter will be incrementend by one. The Name property will be used to register the meter with the OpenTelemetry collector.
Next we initialize an activity source to create traces. Create a new file Diagnostics.cs and add the following code to the file.
|
|
Now you need to edit the Program.cs file to add the OpenTelemetry packages to the application. We will also register the WeatherMeter and the ActivitySource so metrics and traces will be collected. Add the following code to the CreateHostBuilder method.
|
|
This will add the OpenTelemetry packages to the application. It will also configure the OpenTelemetry collector to send the metrics and traces to the local collector.
After that we need to add some code to the WeatherForecastController to generate some metrics and traces.
|
|
On line 26 we start a new activity. This will create a new trace. On line 27 we increment the counter using the method we created earlier in the WeatherMeter.
The application is now ready to create metrics and traces and is able to send them to the open telemetry collector.
Next thing to do is to dockerize the application. Create a Dockerfile to the project and add the following code:
|
|
Now the application is ready to run in a container. To test this we can run the following command:
docker build -t weatherapi .
docker run -p 8080:80 weatherapi
If you head over to http://localhost:8080/weatherforecast you should see the weather forecast data.
Docker compose #
Now we have a working application, we can start with the OpenTelemetry collector. To make this easy we will use docker compose. This will allow us to run multiple containers at the same time.
Create a new file called docker-compose.yml and add the following content:
|
|
In this docker compose file we define 4 services. The weatherapi, the otel-collector, Jaeger and Prometheus. The weatherapi is the application we created earlier. The otel-collector is for retrieving traces and metrics. The jaeger service is the Jaeger UI. The prometheus service is the Prometheus UI. There are some references to configuration files. We will create these files in the next steps. On line we set the OTEL_COLLECTOR_ENDPOINT environment variable to override the default endpoint. This is needed because the default endpoint is not accessible from the weatherapi container.
Configuring the OpenTelemetry collector and Prometheus #
With all services defined the last thing to do is to configure the OpenTelemetry collector. To do this we need to create a new file called otel-collector-config.yaml. Add the following content to the file:
|
|
The most interesting of this part is the jaeger exporter. This one is prefi
Prometheus #
To get metrics in to prometheus we need to configure the prometheus service. To do this we need to create a new file called prometheus-config.yml. Add the following content to the file:
|
|
Running the application #
To run everything we can run the following command:
docker-compose up -d
To see if everything is running we can run the following command:
docker-compose ps
This should see something similar like this:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8550dc8df46b otel/opentelemetry-collector-contrib "/otelcol-contrib --…" 13 hours ago Up 13 hours 0.0.0.0:4317->4317/tcp, 0.0.0.0:55680->55680/tcp, 55678-55679/tcp weatherapi-otel-collector-1
cd22abb5b8df jaegertracing/all-in-one "/go/bin/all-in-one-…" 13 hours ago Up 13 hours 5775/udp, 5778/tcp, 14250/tcp, 6831-6832/udp, 14268/tcp, 0.0.0.0:16686->16686/tcp weatherapi-jaeger-1
1e8e94be8a21 weatherapi "dotnet WeatherApi.d…" 13 hours ago Up 13 hours 80/tcp, 443/tcp weatherapi-weatherapi-1
e1050c408cb3 prom/prometheus "/bin/prometheus --c…" 13 hours ago Up 13 hours 0.0.0.0:9090->9090/tcp weatherapi-prometheus-1
View traces and metrics #
If you now head over to http://localhost:8080/weatherforecast you should see a generated weather forecast.
Open a new tab and go to http://localhost:16686, you should see the Jaeger UI. In the service dropdown menu, select weather-service, after that you should see the traces appear on each request made to the weather forecast service.
If you head over to http://localhost:9090 you should see the Prometheus UI. If you search for weather_requests_total you should see the counter we created earlier. If you click on the graph tab you should see a graph of the counter.
You can find the complete code on my github repo